home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / shells / zsh-3.0-p / zsh-3 / zsh-3.0-pre3 / Src / signals.c < prev    next >
C/C++ Source or Header  |  1996-07-05  |  19KB  |  755 lines

  1. /*
  2.  * $Id: signals.c,v 2.13 1996/07/05 20:52:22 hzoli Exp $
  3.  *
  4.  * signals.c - signals handling code
  5.  *
  6.  * This file is part of zsh, the Z shell.
  7.  *
  8.  * Copyright (c) 1992-1996 Paul Falstad
  9.  * All rights reserved.
  10.  *
  11.  * Permission is hereby granted, without written agreement and without
  12.  * license or royalty fees, to use, copy, modify, and distribute this
  13.  * software and its documentation for any purpose, provided that the
  14.  * above copyright notice and the following two paragraphs appear in
  15.  * all copies of this software.
  16.  *
  17.  * In no event shall Paul Falstad or the Zsh Development Group be liable
  18.  * to any party for direct, indirect, special, incidental, or consequential
  19.  * damages arising out of the use of this software and its documentation,
  20.  * even if Paul Falstad and the Zsh Development Group have been advised of
  21.  * the possibility of such damage.
  22.  *
  23.  * Paul Falstad and the Zsh Development Group specifically disclaim any
  24.  * warranties, including, but not limited to, the implied warranties of
  25.  * merchantability and fitness for a particular purpose.  The software
  26.  * provided hereunder is on an "as is" basis, and Paul Falstad and the
  27.  * Zsh Development Group have no obligation to provide maintenance,
  28.  * support, updates, enhancements, or modifications.
  29.  *
  30.  */
  31.  
  32. #include "zsh.h"
  33.  
  34. /* signals that are trapped = 1, signals ignored = 2 */
  35. int sigtrapped[VSIGCOUNT];
  36.  
  37. /* trap functions for each signal */
  38. List sigfuncs[VSIGCOUNT];
  39.  
  40. /* This is only used on machines that don't understand signal sets.  *
  41.  * On SYSV machines this will represent the signals that are blocked *
  42.  * (held) using sighold.  On machines which can't block signals at   *
  43.  * all, we will simulate this by ignoring them and remembering them  *
  44.  * in this variable.                                                 */
  45. #if !defined(POSIX_SIGNALS) && !defined(BSD_SIGNALS)
  46. static sigset_t blocked_set;
  47. #endif
  48.  
  49. #ifdef POSIX_SIGNALS
  50. # define signal_jmp_buf       sigjmp_buf
  51. # define signal_setjmp(b)     sigsetjmp((b),1)
  52. # define signal_longjmp(b,n)  siglongjmp((b),(n))
  53. #else
  54. # define signal_jmp_buf       jmp_buf
  55. # define signal_setjmp(b)     setjmp(b)
  56. # define signal_longjmp(b,n)  longjmp((b),(n))
  57. #endif
  58.  
  59. #ifdef NO_SIGNAL_BLOCKING
  60. # define signal_process(sig)  signal_ignore(sig)
  61. # define signal_reset(sig)    install_handler(sig)
  62. #else
  63. # define signal_process(sig)  ;
  64. # define signal_reset(sig)    ;
  65. #endif
  66.  
  67. /* Install signal handler for given signal.           *
  68.  * If possible, we want to make sure that interrupted *
  69.  * system calls are not restarted.                    */
  70.  
  71. /**/
  72. void
  73. install_handler(int sig)
  74. {
  75. #ifdef POSIX_SIGNALS
  76.     struct sigaction act;
  77.  
  78.     act.sa_handler = (SIGNAL_HANDTYPE) handler;
  79.     sigemptyset(&act.sa_mask);        /* only block sig while in handler */
  80.     act.sa_flags = 0;
  81. # ifdef SA_INTERRUPT                  /* SunOS 4.x */
  82.     if (interact)
  83.         act.sa_flags |= SA_INTERRUPT; /* make sure system calls are not restarted */
  84. # endif
  85.     sigaction(sig, &act, (struct sigaction *)NULL);
  86. #else
  87. # ifdef BSD_SIGNALS
  88.     struct sigvec vec;
  89.  
  90.     vec.sv_handler = (SIGNAL_HANDTYPE) handler;
  91.     vec.sv_mask = sigmask(sig);    /* mask out this signal while in handler    */
  92. #  ifdef SV_INTERRUPT
  93.     vec.sv_flags = SV_INTERRUPT;   /* make sure system calls are not restarted */
  94. #  endif
  95.     sigvec(sig, &vec, (struct sigvec *)NULL);
  96. # else
  97. #  ifdef SYSV_SIGNALS
  98.     /* we want sigset rather than signal because it will   *
  99.      * block sig while in handler.  signal usually doesn't */
  100.     sigset(sig, handler);
  101. #  else  /* NO_SIGNAL_BLOCKING (bummer) */
  102.     signal(sig, handler);
  103.  
  104. #  endif /* SYSV_SIGNALS  */
  105. # endif  /* BSD_SIGNALS   */
  106. #endif   /* POSIX_SIGNALS */
  107. }
  108.  
  109. /* enable ^C interrupts */
  110.  
  111. /**/
  112. void
  113. intr(void)
  114. {
  115.     if (interact)
  116.         install_handler(SIGINT);
  117. }
  118.  
  119. /* disable ^C interrupts */
  120.  
  121. /**/
  122. void
  123. nointr(void)
  124. {
  125.     if (interact)
  126.         signal_ignore(SIGINT);
  127. }
  128.  
  129. /* temporarily block ^C interrupts */
  130.  
  131. /**/
  132. void
  133. holdintr(void)
  134. {
  135.     if (interact)
  136.         signal_block(signal_mask(SIGINT));
  137. }
  138.  
  139. /* release ^C interrupts */
  140.  
  141. /**/
  142. void
  143. noholdintr(void)
  144. {
  145.     if (interact)
  146.         signal_unblock(signal_mask(SIGINT));
  147. }
  148.  
  149. /* create a signal mask containing *
  150.  * only the given signal           */
  151.  
  152. /**/
  153. sigset_t
  154. signal_mask(int sig)
  155. {
  156.     sigset_t set;
  157.  
  158.     sigemptyset(&set);
  159.     if (sig)
  160.         sigaddset(&set, sig);
  161.     return set;
  162. }
  163.  
  164. /* Block the signals in the given signal *
  165.  * set. Return the old signal set.       */
  166.  
  167. /**/
  168. sigset_t
  169. signal_block(sigset_t set)
  170. {
  171.     sigset_t oset;
  172.  
  173. #ifdef POSIX_SIGNALS
  174.     sigprocmask(SIG_BLOCK, &set, &oset);
  175. #else
  176. # ifdef BSD_SIGNALS
  177.     oset = sigblock(set);
  178. # else
  179. #  ifdef SYSV_SIGNALS
  180.     int i;
  181.  
  182.     oset = blocked_set;
  183.     for (i = 1; i <= NSIG; ++i) {
  184.         if (sigismember(&set, i) && !sigismember(&blocked_set, i)) {
  185.             sigaddset(&blocked_set, i);
  186.             sighold(i);
  187.         }
  188.     }
  189. #  else  /* NO_SIGNAL_BLOCKING */
  190. /* We will just ignore signals if the system doesn't have *
  191.  * the ability to block them.                             */
  192.     int i;
  193.  
  194.     oset = blocked_set;
  195.     for (i = 1; i <= NSIG; ++i) {
  196.         if (sigismember(&set, i) && !sigismember(&blocked_set, i)) {
  197.             sigaddset(&blocked_set, i);
  198.             signal_ignore(i);
  199.         }
  200.    }
  201. #  endif /* SYSV_SIGNALS  */
  202. # endif  /* BSD_SIGNALS   */
  203. #endif   /* POSIX_SIGNALS */
  204.  
  205.     return oset;
  206. }
  207.  
  208. /* Unblock the signals in the given signal *
  209.  * set. Return the old signal set.         */
  210.  
  211. /**/
  212. sigset_t
  213. signal_unblock(sigset_t set)
  214. {
  215.     sigset_t oset;
  216.  
  217. #ifdef POSIX_SIGNALS
  218.     sigprocmask(SIG_UNBLOCK, &set, &oset);
  219. #else
  220. # ifdef BSD_SIGNALS
  221.     sigfillset(&oset);
  222.     oset = sigsetmask(oset);
  223.     sigsetmask(oset & ~set);
  224. # else
  225. #  ifdef SYSV_SIGNALS
  226.     int i;
  227.  
  228.     oset = blocked_set;
  229.     for (i = 1; i <= NSIG; ++i) {
  230.         if (sigismember(&set, i) && sigismember(&blocked_set, i)) {
  231.             sigdelset(&blocked_set, i);
  232.             sigrelse(i);
  233.         }
  234.     }
  235. #  else  /* NO_SIGNAL_BLOCKING */
  236. /* On systems that can't block signals, we are just ignoring them.  So *
  237.  * to unblock signals, we just reenable the signal handler for them.   */
  238.     int i;
  239.  
  240.     oset = blocked_set;
  241.     for (i = 1; i <= NSIG; ++i) {
  242.         if (sigismember(&set, i) && sigismember(&blocked_set, i)) {
  243.             sigdelset(&blocked_set, i);
  244.             install_handler(i);
  245.         }
  246.    }
  247. #  endif /* SYSV_SIGNALS  */
  248. # endif  /* BSD_SIGNALS   */
  249. #endif   /* POSIX_SIGNALS */
  250.  
  251.     return oset;
  252. }
  253.  
  254. /* set the process signal mask to *
  255.  * be the given signal mask       */
  256.  
  257. /**/
  258. sigset_t
  259. signal_setmask(sigset_t set)
  260. {
  261.     sigset_t oset;
  262.  
  263. #ifdef POSIX_SIGNALS
  264.     sigprocmask(SIG_SETMASK, &set, &oset);
  265. #else
  266. # ifdef BSD_SIGNALS
  267.     oset = sigsetmask(set);
  268. # else
  269. #  ifdef SYSV_SIGNALS
  270.     int i;
  271.  
  272.     oset = blocked_set;
  273.     for (i = 1; i <= NSIG; ++i) {
  274.         if (sigismember(&set, i) && !sigismember(&blocked_set, i)) {
  275.             sigaddset(&blocked_set, i);
  276.             sighold(i);
  277.         } else if (!sigismember(&set, i) && sigismember(&blocked_set, i)) {
  278.             sigdelset(&blocked_set, i);
  279.             sigrelse(i);
  280.         }
  281.     }
  282. #  else  /* NO_SIGNAL_BLOCKING */
  283.     int i;
  284.  
  285.     oset = blocked_set;
  286.     for (i = 1; i < NSIG; ++i) {
  287.         if (sigismember(&set, i) && !sigismember(&blocked_set, i)) {
  288.             sigaddset(&blocked_set, i);
  289.             signal_ignore(i);
  290.         } else if (!sigismember(&set, i) && sigismember(&blocked_set, i)) {
  291.             sigdelset(&blocked_set, i);
  292.             install_handler(i);
  293.         }
  294.     }
  295. #  endif /* SYSV_SIGNALS  */
  296. # endif  /* BSD_SIGNALS   */
  297. #endif   /* POSIX_SIGNALS */
  298.  
  299.     return oset;
  300. }
  301.  
  302. #if defined(NO_SIGNAL_BLOCKING)
  303. static int suspend_longjmp = 0;
  304. static signal_jmp_buf suspend_jmp_buf;
  305. #endif
  306.  
  307. /**/
  308. int
  309. signal_suspend(int sig, int sig2)
  310. {
  311.     int ret;
  312.  
  313. #ifdef POSIX_SIGNALS
  314.     sigset_t set;
  315.  
  316.     sigfillset(&set);
  317.     sigdelset(&set, sig);
  318.     sigdelset(&set, SIGHUP);  /* still don't know why we add this? */
  319.     if (sig2)
  320.         sigdelset(&set, sig2);
  321.     ret = sigsuspend(&set);
  322. #else
  323. # ifdef BSD_SIGNALS
  324.     sigset_t set;
  325.  
  326.     sigfillset(&set);
  327.     sigdelset(&set, sig);
  328.     if (sig2)
  329.       sigdelset(&set, sig2);
  330.     ret = sigpause(set);
  331. # else
  332. #  ifdef SYSV_SIGNALS
  333.     ret = sigpause(sig);
  334.  
  335. #  else  /* NO_SIGNAL_BLOCKING */
  336.     /* need to use signal_longjmp to make this race-free *
  337.      * between the child_unblock() and pause()           */
  338.     if (signal_setjmp(suspend_jmp_buf) == 0) {
  339.         suspend_longjmp = 1;   /* we want to signal_longjmp after catching signal */
  340.         child_unblock();       /* do we need to unblock sig2 as well?             */
  341.         ret = pause();
  342.     }
  343.     suspend_longjmp = 0;       /* turn off using signal_longjmp since we are past *
  344.                                 * the pause() function.                           */
  345. #  endif /* SYSV_SIGNALS  */
  346. # endif  /* BSD_SIGNALS   */
  347. #endif   /* POSIX_SIGNALS */
  348.  
  349.     return ret;
  350. }
  351.  
  352.  
  353. /* Use a circular queue to save signals caught during    *
  354.  * critical sections of code.  You call queue_signals to *
  355.  * start queueing, and unqueue_signals to process the    *
  356.  * queue and stop queueing.  Since the kernel doesn't    *
  357.  * queue signals, it is probably overkill for zsh to do  *
  358.  * this, but it shouldn't hurt anything to do it anyway. */
  359.  
  360. /* Right now I'm queueing all signals, but maybe we only *
  361.  * need to queue SIGCHLD.  Anybody know?                 */
  362.  
  363.  
  364. #define MAX_QUEUE_SIZE 16
  365.  
  366. static int queueing_enabled;
  367. static sigset_t signal_mask_queue[MAX_QUEUE_SIZE];
  368. static int signal_queue[MAX_QUEUE_SIZE];
  369. static int queue_front = 0;
  370. static int queue_rear = 0;
  371.  
  372. /* Start queueing up any received signals rather *
  373.  * than handling them.                           */
  374.  
  375. /**/
  376. void
  377. queue_signals(void)
  378. {
  379.     queueing_enabled++;        /* signals are now being queued */
  380. }
  381.  
  382. /* Process all queued signals */
  383.  
  384. /**/
  385. void
  386. unqueue_signals(void)
  387. {
  388.     DPUTS(!queueing_enabled, "BUG: unqueue_signals called but not queueing");
  389.     if (--queueing_enabled)
  390.     return;
  391.  
  392.     while (queue_front != queue_rear) {            /* while signals in queue */
  393.     sigset_t oset;
  394.         queue_front = ++queue_front % MAX_QUEUE_SIZE;
  395.         oset = signal_setmask(signal_mask_queue[queue_front]);
  396.         handler(signal_queue[queue_front]);        /* handle queued signal   */
  397.     signal_setmask(oset);
  398.     }
  399. }
  400.  
  401. /* What flavor of waitpid/wait3/wait shall we use? */
  402.  
  403. #ifdef HAVE_WAITPID
  404. # define  WAIT(pid, statusp, options) waitpid(pid, statusp, options)
  405. #else
  406. # ifdef HAVE_WAIT3
  407. #  define WAIT(pid, statusp, options) wait3((void *) statusp, options, NULL)
  408. # else
  409. #  define WAIT(pid, statusp, options) wait(statusp)
  410. # endif
  411. #endif
  412.  
  413. /* the signal handler */
  414.  
  415. /**/
  416. RETSIGTYPE
  417. handler(int sig)
  418. {
  419.     sigset_t newmask, oldmask;
  420.  
  421. #if defined(NO_SIGNAL_BLOCKING)
  422.     int do_jump;
  423.     signal_jmp_buf jump_to;
  424. #endif
  425.  
  426.     signal_process(sig);
  427.  
  428.     sigfillset(&newmask);
  429.     oldmask = signal_block(newmask);        /* Block all signals temporarily           */
  430.  
  431. #if defined(NO_SIGNAL_BLOCKING)
  432.     do_jump = suspend_longjmp;              /* do we need to longjmp to signal_suspend */
  433.     suspend_longjmp = 0;                    /* In case a SIGCHLD somehow arrives       */
  434.  
  435.     if (sig == SIGCHLD) {                   /* Traps can cause nested child_suspend()  */
  436.         if (do_jump)
  437.             jump_to = suspend_jmp_buf;      /* Copy suspend_jmp_buf                    */
  438.     }
  439. #endif
  440.  
  441.     if (queueing_enabled) {           /* Are we queueing signals now?      */
  442.         int temp_rear = ++queue_rear % MAX_QUEUE_SIZE;
  443.  
  444.     DPUTS(temp_rear == queue_front, "BUG: signal queue full");
  445.         if (temp_rear != queue_front) { /* Make sure it's not full (extremely unlikely) */
  446.             queue_rear = temp_rear;                  /* ok, not full, so add to queue   */
  447.             signal_queue[queue_rear] = sig;          /* save signal caught              */
  448.             signal_mask_queue[queue_rear] = oldmask; /* save current signal mask        */
  449.         }
  450.         signal_reset(sig);
  451.         return;
  452.     }
  453.  
  454.     signal_setmask(oldmask);          /* Reset signal mask, signal traps ok now */
  455.  
  456.     switch (sig) {
  457.     case SIGCHLD:
  458.  
  459.     /* keep WAITING until no more child processes to reap */
  460.     for (;;)
  461.       cont: {
  462.             int old_errno = errno; /* save the errno, since WAIT may change it */
  463.         int status;
  464.         Job jn;
  465.         Process pn;
  466.             pid_t pid;
  467.         pid_t *procsubpid = &cmdoutpid;
  468.         int *procsubval = &cmdoutval;
  469.         struct execstack *es = exstack;
  470.  
  471.             pid = WAIT(-1, &status, WNOHANG|WUNTRACED);  /* reap the child process */
  472.  
  473.             if (!pid)  /* no more children to reap */
  474.                 break;
  475.  
  476.         /* check if child returned was from process substitution */
  477.         for (;;) {
  478.         if (pid == *procsubpid) {
  479.             *procsubpid = 0;
  480.             if (WIFSIGNALED(status)) {
  481.             *procsubval = (0200 | WTERMSIG(status));
  482.             if (WTERMSIG(status) == SIGINT)
  483.                 kill(getpid(), SIGINT);
  484.             else if (sigtrapped[WTERMSIG(status)])
  485.                 dotrap(WTERMSIG(status));
  486.             } else
  487.             *procsubval = WEXITSTATUS(status);
  488.             goto cont;
  489.         }
  490.         if (!es)
  491.             break;
  492.         procsubpid = &es->cmdoutpid;
  493.         procsubval = &es->cmdoutval;
  494.         es = es->next;
  495.         }
  496.  
  497.         /* check for WAIT error */
  498.             if (pid == -1) {
  499.                 if (errno != ECHILD)
  500.                     zerr("wait failed: %e", NULL, errno);
  501.                 errno = old_errno;    /* WAIT changed errno, so restore the original */
  502.                 break;
  503.             }
  504.  
  505.         /* Find the process and job containing this pid and update it. */
  506.         if (findproc(pid, &jn, &pn)) {
  507.         update_process(pn, status);
  508.         update_job(jn);
  509.         }
  510.         }
  511.         break;
  512.  
  513.     case SIGHUP:
  514.         if (sigtrapped[SIGHUP])
  515.             dotrap(SIGHUP);
  516.         else {
  517.             stopmsg = 1;
  518.             zexit(SIGHUP, 1);
  519.         }
  520.         break;
  521.  
  522.     case SIGINT:
  523.         if (sigtrapped[SIGINT])
  524.             dotrap(SIGINT);
  525.         else {
  526.             extern int list_pipe, simple_pline;
  527.  
  528.             if (list_pipe || chline || simple_pline) {
  529.                 breaks = loops;
  530.                 errflag = 1;
  531.             }
  532.         }
  533.         break;
  534.  
  535.     case SIGWINCH:
  536.         adjustwinsize();  /* check window size and adjust */
  537.         break;
  538.  
  539.     case SIGALRM:
  540.         if (sigtrapped[SIGALRM]) {
  541.         int tmout;
  542.             dotrap(SIGALRM);
  543.             if ((tmout = getiparam("TMOUT")))
  544.                 alarm(tmout);           /* reset the alarm */
  545.         } else {
  546.         int idle = ttyidlegetfn(NULL);
  547.         int tmout = getiparam("TMOUT");
  548.         if (idle >= 0 && idle < tmout)
  549.         alarm(tmout - idle);
  550.         else {
  551.         zerr("timeout", NULL, 0);
  552.         stopmsg = 1;
  553.         zexit(SIGALRM, 1);
  554.         }
  555.         }
  556.         break;
  557.  
  558.     default:
  559.         dotrap(sig);
  560.         break;
  561.     }   /* end of switch(sig) */
  562.  
  563.     signal_reset(sig);
  564.  
  565. /* This is used to make signal_suspend() race-free */
  566. #if defined(NO_SIGNAL_BLOCKING)
  567.     if (do_jump)
  568.         signal_longjmp(jump_to, 1);
  569. #endif
  570.  
  571. } /* handler */
  572.  
  573.  
  574. /* SIGHUP any jobs left running */
  575.  
  576. /**/
  577. void
  578. killrunjobs(int from_signal)
  579. {
  580.     int i, killed = 0;
  581.  
  582.     if (isset(NOHUP))
  583.         return;
  584.     for (i = 1; i < MAXJOB; i++)
  585.         if ((from_signal || i != thisjob) && (jobtab[i].stat & STAT_LOCKED) &&
  586.             !(jobtab[i].stat & STAT_NOPRINT) &&
  587.             !(jobtab[i].stat & STAT_STOPPED)) {
  588.             if (killpg(jobtab[i].gleader, SIGHUP) != -1)
  589.                 killed++;
  590.         }
  591.     if (killed)
  592.         zerr("warning: %d jobs SIGHUPed", NULL, killed);
  593. }
  594.  
  595.  
  596. /* send a signal to a job (simply involves kill if monitoring is on) */
  597.  
  598. /**/
  599. int
  600. killjb(Job jn, int sig)
  601. {
  602.     Process pn;
  603.     int err = 0;
  604.  
  605.     if (jobbing) {
  606.         if (jn->stat & STAT_SUPERJOB) {
  607.             if (sig == SIGCONT) {
  608.                 for (pn = jobtab[jn->other].procs; pn; pn = pn->next)
  609.                     kill(pn->pid, sig);
  610.  
  611.                 for (pn = jn->procs; pn->next; pn = pn->next)
  612.                     err = kill(pn->pid, sig);
  613.  
  614.                 return err;
  615.             }
  616.  
  617.             killpg(jobtab[jn->other].gleader, sig);
  618.             return killpg(jn->gleader, sig);
  619.         }
  620.         else
  621.             return (killpg(jn->gleader, sig));
  622.     }
  623.     for (pn = jn->procs; pn; pn = pn->next)
  624.         if ((err = kill(pn->pid, sig)) == -1 && errno != ESRCH)
  625.             return -1;
  626.     return err;
  627. }
  628.  
  629. /**/
  630. void
  631. settrap(int sig, List l)
  632. {
  633.     Cmd c;
  634.  
  635.     if (l && l->left && l->left->left) {
  636.         c = l->left->left->left;
  637.         if (c && c->type == SIMPLE && empty(c->args) && empty(c->redir)
  638.             && empty(c->vars) && !c->flags)
  639.             l = NULL;
  640.     }
  641.     if (sig == -1)
  642.         return;
  643.     if (jobbing && (sig == SIGTTOU || sig == SIGTSTP ||
  644.             sig == SIGTTIN || sig == SIGPIPE)) {
  645.         zerr("can't trap SIG%s in interactive shells", sigs[sig], 0);
  646.         return;
  647.     }
  648.     if (sigfuncs[sig])
  649.         freestruct(sigfuncs[sig]);
  650.     if (!l) {
  651.         sigtrapped[sig] = 2;
  652.         sigfuncs[sig] = NULL;
  653.         if (sig && sig <= SIGCOUNT &&
  654. #ifdef SIGWINCH
  655.             sig != SIGWINCH &&
  656. #endif
  657.             sig != SIGCHLD)
  658.             signal_ignore(sig);
  659.     } else {
  660.         if (sig && sig <= SIGCOUNT &&
  661. #ifdef SIGWINCH
  662.             sig != SIGWINCH &&
  663. #endif
  664.             sig != SIGCHLD)
  665.             install_handler(sig);
  666.         sigtrapped[sig] = 1;
  667.         PERMALLOC {
  668.         sigfuncs[sig] = (List) dupstruct(l);
  669.         } LASTALLOC;
  670.     }
  671. }
  672.  
  673. /**/
  674. void
  675. unsettrap(int sig)
  676. {
  677.     if (sig == -1)
  678.         return;
  679.     if (jobbing && (sig == SIGTTOU || sig == SIGTSTP ||
  680.             sig == SIGTTIN || sig == SIGPIPE)) {
  681.         return;
  682.     }
  683.     sigtrapped[sig] = 0;
  684.     if (sig == SIGINT && interact) {
  685.     /* PWS 1995/05/16:  added test for interactive, also noholdintr()
  686.      * as subshells ignoring SIGINT have it blocked from delivery
  687.      */
  688.         intr();
  689.     noholdintr();
  690.     } else if (sig == SIGHUP)
  691.         install_handler(sig);
  692.     else if (sig && sig <= SIGCOUNT &&
  693. #ifdef SIGWINCH
  694.              sig != SIGWINCH &&
  695. #endif
  696.              sig != SIGCHLD)
  697.         signal_default(sig);
  698.     if (sigfuncs[sig]) {
  699.         freestruct(sigfuncs[sig]);
  700.         sigfuncs[sig] = NULL;
  701.     }
  702. }
  703.  
  704. /* Execute a trap function for a given signal */
  705.  
  706. /**/
  707. void
  708. dotrap(int sig)
  709. {
  710.     LinkList args;
  711.     char *name, num[4];
  712.     int sav = sigtrapped[sig];
  713.  
  714.     /* if signal is being ignored or the trap function              *
  715.      * is NULL, then return                          *
  716.      *                                      *
  717.      * Also return if errflag is set.  In fact, the code in the       *
  718.      * function will test for this, but this way we keep status flags *
  719.      * intact without working too hard.  Special cases (e.g. calling  *
  720.      * a trap for SIGINT after the error flag was set) are handled    *
  721.      * by the calling code.  (PWS 1995/06/08).                  */
  722.     if (sav == 2 || !sigfuncs[sig] || errflag)
  723.         return;
  724.  
  725.     sigtrapped[sig] = 2;
  726.  
  727.     lexsave();
  728.     execsave();
  729.     PERMALLOC {
  730.     args = newlinklist();
  731.     name = (char *) zalloc(5 + strlen(sigs[sig]));
  732.     sprintf(name, "TRAP%s", sigs[sig]);
  733.     addlinknode(args, name);
  734.     sprintf(num, "%d", sig);
  735.     addlinknode(args, num);
  736.     } LASTALLOC;
  737.     trapreturn = -1;
  738.     doshfunc(sigfuncs[sig], args, 0, 1);
  739.     execrestore();
  740.     lexrestore();
  741.     freelinklist(args, (FreeFunc) NULL);
  742.     zsfree(name);
  743.  
  744.     if (trapreturn > 0) {
  745.     breaks = loops;
  746.     errflag = 1;
  747.     } else {
  748.     trapreturn = 0;
  749.     }
  750.  
  751.     if (sigtrapped[sig])
  752.     sigtrapped[sig] = sav;
  753. }
  754.  
  755.